#include "Dispenser.h"

void Dispenser::begin(uint8_t servoPin) {
  _servo.attach(servoPin);
  _servo.write(0); // retracted
}

void Dispenser::startPlantCycle() {
  if (isBusy()) return;
  _state = DispenseState::EXTENDING;
  _stateStartMs = millis();
  _servo.write(90); // extend: bore the hole
}

void Dispenser::update(unsigned long nowMs, bool hopperHasSeedLive) {
  unsigned long elapsed = nowMs - _stateStartMs;

  switch (_state) {
    case DispenseState::IDLE:
      break;

    case DispenseState::EXTENDING:
      if (elapsed >= Dispensing::EXTEND_MS) {
        _state = DispenseState::SETTLING;
        _stateStartMs = nowMs;
      }
      break;

    case DispenseState::SETTLING:
      if (elapsed >= Dispensing::SETTLE_MS) {
        _seedDetectedThisCycle = hopperHasSeedLive;
        _servo.write(0); // begin retracting
        _state = DispenseState::RETRACTING;
        _stateStartMs = nowMs;
      }
      break;

    case DispenseState::RETRACTING:
      if (elapsed >= Dispensing::RETRACT_MS) {
        if (_seedDetectedThisCycle) {
          _sessionSeedCount++;
          _emptyStreak = 0;
        } else {
          if (_emptyStreak < 255) _emptyStreak++;
          if (_emptyStreak >= Thresholds::HOPPER_EMPTY_STREAK_LIMIT) _hopperEmpty = true;
        }
        _cycleCompletePending = true;
        _state = DispenseState::IDLE;
      }
      break;
  }
}

bool Dispenser::consumeCompletedCycle(bool &seedDetectedOut) {
  if (!_cycleCompletePending) return false;
  seedDetectedOut = _seedDetectedThisCycle;
  _cycleCompletePending = false;
  return true;
}

void Dispenser::refillHopper() {
  _hopperEmpty = false;
  _emptyStreak = 0;
}

void Dispenser::resetSessionCount() {
  _sessionSeedCount = 0;
}
